package it.polimi.jita.cp.block.de;

import it.polimi.jita.cp.block.Block;
import it.polimi.jita.cp.block.Headers;
import it.polimi.jita.cp.block.de.Histogram.Bin;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.TexturePaint;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.csv.CSVRecord;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

/**
 * 
 * @author Federico Monterisi
 *
 *
 */
public class DemandEstimator extends
		Block<DemandEstimatorInput, DemandEstimatorOutput> {

	private static final Double WAIT_LIMIT = 0.01d;

	protected DemandEstimatorOutput computeOutput() {
		System.out.println(String.format("Computation of new capacity"));

		List<IInstantDemandEstimatorData> instants = getInput().getInstants();

		// Create the histogram of demand
		Histogram histogram = new Histogram(100, 0, 1);

		for (IInstantDemandEstimatorData instant : instants) {
			Double waitP = instant.getWait();
			Double runP = instant.getRun();
			if (waitP.compareTo(WAIT_LIMIT) < 0)
				histogram.incrementBinValueGEQ(runP.doubleValue());
			else
				histogram.incrementBinValue(runP.doubleValue());
		}

		// Estimate the demand
		for (IInstantDemandEstimatorData instant : instants) {
			Double waitP = instant.getWait();
			Double runP = instant.getRun();
			if (waitP.compareTo(WAIT_LIMIT) < 0)
				instant.setDemand(histogram.sampleGEQ(runP.doubleValue()));
			else
				instant.setDemand(runP.doubleValue());

		}
		return new DemandEstimatorOutput(instants, histogram);
	}

	@Override
	protected Set<JFreeChart> createCharts() {
		Set<JFreeChart> set = new HashSet<>();
		set.add(getDemandHistogram());
		set.add(getDemandChart());
		return set;

	}

	private JFreeChart getDemandHistogram() {

		List<Bin> bins = getOutput().getHistogram().getBins();
		DefaultCategoryDataset bardataset = new DefaultCategoryDataset();

		for (Bin bin : bins) {
			String name = String.format("%s-%s",
					bin.getLowerBound().multiply(100).intValue(), bin
							.getUpperBound().multiply(100).intValue());
			bardataset.setValue(bin.getValue().doubleValue(), "dd", name);
		}

		JFreeChart barchart = ChartFactory.createBarChart(
				"Demand distribution histogram", // Title
				"Demand", // X-axis Label
				"Frequency", // Y-axis Label
				bardataset, // Dataset
				PlotOrientation.VERTICAL, // Plot orientation
				false, // Show legend
				true, // Use tooltips
				false // Generate URLs
				);

		return barchart;
	}

	private JFreeChart getDemandChart() {
		// Create a simple XY chart
		XYSeries runSeries = new XYSeries("Run");
		XYSeries demandSeries = new XYSeries("Demand");
		List<Double> demand = getOutput().getDemandEstimationDbl();
		List<IInstantDemandEstimatorData> instants = getInput().getInstants();
		for (int i = 0; i < instants.size(); i++) {
			demandSeries.add(i + 1, demand.get(i));
			runSeries.add(i + 1, instants.get(i).getRun().doubleValue());
		}

		// Add the series to your data set
		XYSeriesCollection dataset = new XYSeriesCollection();

		dataset.addSeries(runSeries);
		dataset.addSeries(demandSeries);

		// Generate the graph
		JFreeChart chart = ChartFactory.createXYAreaChart("Demand estimation", // Title
				"Time (instants)", // x-axis Label
				"Capacity (%)", // y-axis Label
				dataset, // Dataset
				PlotOrientation.VERTICAL, // Plot Orientation
				true, // Show Legend
				true, // Use tooltips
				false // Configure chart to generate URLs?
				);
		chart.setBackgroundImageAlpha(0.5f);
		chart.getXYPlot().setBackgroundPaint(new Color(230, 230, 230));
		chart.getXYPlot().setForegroundAlpha(1.0f);
		chart.getXYPlot().getDomainAxis().setRange(1, demand.size());

		chart.getXYPlot().getRenderer()
				.setSeriesPaint(0, Color.decode("#fab900"));
		chart.getXYPlot().getRenderer()
				.setSeriesPaint(1, Color.decode("#004586aa"));

		XYItemRenderer renderer = chart.getXYPlot().getRenderer();

		// Set a pattern
		BufferedImage bi = new BufferedImage(3, 3, BufferedImage.TYPE_INT_ARGB);
		Graphics g = bi.getGraphics();
		g.setColor(Color.decode("#004586aa"));
		g.drawLine(0, 0, 3, 3);
		TexturePaint tp = new TexturePaint(bi, new Rectangle(0, 0, 3, 3));
		renderer.setSeriesPaint(1, tp);

		return chart;
	}

	@Override
	public Map<List<CSVRecord>, CSVRecord> createCSVFiles() {

		Map<List<CSVRecord>, CSVRecord> map = new HashMap<>();
		CSVRecord header = createCSVRecord(true, Headers.CAPACITY_DEMAND);
		List<CSVRecord> records = new ArrayList<>();
		List<Double> capDems = getOutput().getDemandEstimationDbl();
		for (Double cd : capDems) {
			records.add(createCSVRecord(false, cd));
		}
		map.put(records, header);
		return map;
	}

}
